package com.mulesoft.domain.analyzer;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import com.mulesoft.domain.analyzer.structure.GraphList;
import com.mulesoft.domain.analyzer.structure.Pair;

public class MinimumWaysWithDistanceCalculator {
	
		private GraphList graph;
		private Set<PathInfo> minimusWay = new HashSet<PathInfo>();
		private Integer minimusLength = Integer.MAX_VALUE;
		
		public static class PathInfo {
			String path;
			public Integer length;
		}
		
		public MinimumWaysWithDistanceCalculator(String input) {
			this.graph = new GraphList(input);
		}
		
		public Set<PathInfo> calculateMinimunWays(char current, char destination) {
			this.minimusLength = Integer.MAX_VALUE;
			this.minimusWay.clear();
			calculateMinimunWays(current, destination, 0, "" + current);
			return this.minimusWay;
		}
		
		public void calculateMinimunWays(char current, char destination, int acumulatedDistance, String acumulatedPath) {
			if (current == destination) {
				PathInfo data = new PathInfo();
				data.length = acumulatedDistance;
				data.path = acumulatedPath;
				
				if (acumulatedDistance > 0) {
					if (this.minimusWay.isEmpty()) {
						// This is the first solution found and the minimum till now.
						this.minimusWay.add(data);
						this.minimusLength = acumulatedDistance;
						return;
					} else if (acumulatedDistance == this.minimusLength) {
						this.minimusWay.add(data);
						return;
					} else if (acumulatedDistance < this.minimusLength) {
						this.minimusWay.clear();
						this.minimusWay.add(data);
						return;
					} else {
						return;
					}
				}
			}
			
			
			// Here is the recursive step since there are not all possibilities yet.
			List<Pair<Character, Integer>> neighbors = graph.getNeighbors(current);
			for (Pair<Character, Integer> neighbor : neighbors) {
				
				//Here I ask if the distance to the neighbor exceed the maximum left.
				// if so, it goes to the next.
				if(acumulatedDistance + neighbor.getSecond() > this.minimusLength) {
					continue;
				}
				
				if (acumulatedPath.contains(""+neighbor.getFirst())&& !acumulatedPath.startsWith(""+neighbor.getFirst())) {
					continue;
				}
				
				calculateMinimunWays(neighbor.getFirst(), destination, acumulatedDistance + neighbor.getSecond(), acumulatedPath + "," + neighbor.getFirst());
			}
			
		}

}
